<?php
include_once 'CzApiEnum.php';

$config = include_once 'config.php';


function error($msg = 'fail', $code = 500)
{
    $result = [
        'code' => $code,
        'msg' => $msg,
    ];
    exit(json_encode($result, JSON_UNESCAPED_UNICODE));
}
function success(array $data = [], string $msg = 'success')
{
    $result = [
        'code' => 200,
        'msg' => $msg,
    ];
    $result = array_merge($result, $data);
    exit(json_encode($result, JSON_UNESCAPED_UNICODE));
}
function get_api_secret($salt)
{
    global $config;
    return md5($salt . $config['API_USER_KEY'] . md5($salt));
}

function api_sign($params, $api_key)
{
    /*
    unset($params['sign']);
    //为空参数不参与签名
    foreach ($params as $k=>$v){
        if(empty($v)){
            unset($params[$k]);
        }
    }
    ksort($params);
    $params['apikey'] = $api_key;
    $str = http_build_query($params);
    $str = urldecode($str);
    */
    $str = api_sign_str($params, $api_key);
    $sign = md5($str);
    return strtoupper($sign);
}
function api_sign_str($params, $api_key)
{
    unset($params['sign']);
    //为空参数不参与签名
    foreach ($params as $k => $v) {
        if (empty($v)) {
            unset($params[$k]);
        }
    }
    ksort($params);
    $params['apikey'] = $api_key;
    $str = http_build_query($params);
    $str = urldecode($str);
    return $str;
}
function check_base_params($params)
{
    $act = $params['act'] ?? '';;
    $uid = $params['uid'] ?? 0;;
    $timestamp = $params['timestamp'] ?? 0;;
    $sign = $params['sign'] ?? '';;
    if (!$act) {
        error('缺少参数：act', CzApiEnum::PARAMS_EMPTY_CODE);
    }
    if (!$uid) {
        error('缺少参数：uid', CzApiEnum::PARAMS_EMPTY_CODE);
    }
    if (!$timestamp) {
        error('缺少参数：timestamp', CzApiEnum::PARAMS_EMPTY_CODE);
    }
    if (!$sign) {
        error('缺少参数：sign', CzApiEnum::PARAMS_EMPTY_CODE);
    }

    $now_timestamp = time();
    if ($now_timestamp - $timestamp > 60) {
        error(CzApiEnum::TIMESTAMP_OUT, CzApiEnum::TIMESTAMP_OUT_CODE);
    }
}

function check_submit_sign($params, $api_secret)
{
    $api_key = get_api_secret($api_secret);
    $api_sign = api_sign($params, $api_key);
    if ($api_sign != $params['sign']) {
        error(CzApiEnum::API_SIGN_ERROR, CzApiEnum::API_SIGN_ERROR_CODE);
    }
}

function get_channel_obj($channel_id, $db)
{
    global $config;
    //    $channel = $db->db_getRow('SELECT * FROM cz_channel WHERE id =:channel_id limit 1',[':channel_id'=> intval($channel_id)]);
    $channel = select_table_one($db, 'cz_channel', [
        'id' => $channel_id,
    ]);

    if (!$channel) {
        error('渠道不存在');
    }



    $channel_file = "../channel/template/{$channel['channel_code']}.php";
    if (!file_exists($channel_file)) {
        error('渠道驱动不存在');
    }

    $setting_arr = unserialize($channel['setting']);
    $setting = [];
    foreach ($setting_arr as $v) {
        $setting[$v['name']] = $v['val'];
    }
    $setting['channel_code'] = $channel['channel_code'];
    $setting['channel_id'] = $channel_id;
    //    $setting['callback_url'] = str_replace('/queue.php','',$config['QUEUE_URL'])."/callback.php?c={$channel['channel_code']}&id={$channel_id}";;
    $setting['callback_url'] = str_replace('/queue.php', '', $config['QUEUE_URL']) . "/callback.php/{$channel['channel_code']}/{$channel_id}";;

    include_once $channel_file;

    $obj = new $channel['channel_code']($setting);
    return $obj;
}

function sock_post($url, $param)
{
    $host = parse_url($url, PHP_URL_HOST);
    $port = parse_url($url, PHP_URL_PORT) ? intval(parse_url($url, PHP_URL_PORT)) : 80;
    $errno = '';
    $errstr = '';
    $timeout = 30;

    $data = http_build_query($param);

    // create connect
    $fp = fsockopen($host, $port, $errno, $errstr, $timeout);

    if (!$fp) {
        return false;
    }

    // send request
    $out = "POST {$url} HTTP/1.1\r\n";
    $out .= "Host:{$host}\r\n";
    $out .= "Content-type:application/x-www-form-urlencoded\r\n";
    $out .= "Content-length:" . strlen($data) . "\r\n";
    $out .= "Connection:close\r\n\r\n";
    $out .= "{$data}";

    fwrite($fp, $out);

    //忽略执行结果；否则等待返回结果
    if (false) {
        $ret = '';
        while (!feof($fp)) {
            $ret .= fgets($fp, 128);
        }
    }
    //20毫秒
    usleep(20000); //fwrite之后马上执行fclose，nginx会直接返回499
    fclose($fp);
}
function sock_get($url, $param)
{
    $host = parse_url($url, PHP_URL_HOST);
    $port = parse_url($url, PHP_URL_PORT) ? intval(parse_url($url, PHP_URL_PORT)) : 80;
    $errno = '';
    $errstr = '';
    $timeout = 30;

    $url = $url . '?' . http_build_query($param);
    // create connect
    $fp = fsockopen($host, $port, $errno, $errstr, $timeout);
    // file_put_contents("../api_resource/logs/" . date("Ymd") . "_queuedata.log", $url . "--url111--" . $url . PHP_EOL, FILE_APPEND);
    // file_put_contents("url.txt", $url . PHP_EOL . $url . PHP_EOL, FILE_APPEND);

    if (!$fp) {
        return false;
    }

    // send request
    $out = "GET {$url} HTTP/1.1\r\n";
    $out .= "Host:{$host}\r\n";
    $out .= "Connection:close\r\n\r\n";


    fwrite($fp, $out);

    //忽略执行结果；否则等待返回结果
    if (false) {
        $ret = '';
        while (!feof($fp)) {
            $ret .= fgets($fp, 128);
        }
        file_put_contents("url.txt", $url . PHP_EOL . $ret . PHP_EOL, FILE_APPEND);
    }


    usleep(20000); //fwrite之后马上执行fclose，nginx会直接返回499
    fclose($fp);
}

function get_order_channel_ids($db, $user, $params, $order)
{
    $product_id = $params['product_id'];
    $spec_id = $params['spec_id'];
    /**************** 拦截 ***************/

    /**************** 拦截 ***************/
    if ($user['group_id'] > 0) {
        //客户分组产品
        $user_group_product = select_table_one($db, 'cz_user_group_product', [
            'product_id' => intval($product_id),
            'spec_id' => intval($spec_id),
            'user_group_id' => intval($user['group_id'])

        ]);

        $is_loop = $user_group_product['is_loop'];
        $channel_group_id = $user_group_product['channel_group_id'];
        //分配渠道排序方式
        $channel_sort_type = $user_group_product['sort_type'];
        if ($channel_group_id > 0) {
            //如果是渠道组 按渠道组的排序方式走
            $channel_group_info = select_table_one($db, 'cz_channel_group', [
                'id' => intval($channel_group_id)
            ]);
            $channel_sort_type = $channel_group_info['sort_type'];
        }

        //获取分配产品渠道的ID
        if ($channel_group_id > 0) {
            $order_channel_id_and_nums = select_table_colom_muti(
                $db,
                'cz_channel_group_item',
                [
                    'channel_group_id' => intval($channel_group_id)
                ],
                [
                    ["CONCAT_WS('-',channel_id,submit_nums) as channel_id"]
                ]
            );
        } else {
            $order_channel_id_and_nums = select_table_colom_muti(
                $db,
                'cz_user_group_product_channel',
                [
                    'user_group_product_id' => $user_group_product['id']
                ],
                [
                    ["CONCAT_WS('-',channel_id,submit_nums) as channel_id"]
                ]
            );
        }
    } else {
        //客户产品
        $user_product = select_table_one($db, 'cz_customer_product', [
            'product_id' => intval($product_id),
            'spec_id' => intval($spec_id),
            'user_id' => $user['id']
        ]);
        if (!$user_product) {
            //不存在的产品，记录日志
            file_put_contents("../api_resource/logs/" . date("Ymd") . "_queue_ll.log",  "[" . date("Y-m-d H:i:s") . "]" . "不存在客户产品" . print_r($order, 1) . PHP_EOL, FILE_APPEND);
        }
        $is_loop = $user_product['is_loop'];
        $channel_group_id = $user_product['channel_group_id'];

        //分配渠道排序方式
        $channel_sort_type = $user_product['sort_type'];
        if ($channel_group_id > 0) {
            //如果是渠道组 按渠道组的排序方式走
            $channel_group_info = select_table_one($db, 'cz_channel_group', [
                'id' => intval($channel_group_id)
            ]);
            $channel_sort_type = $channel_group_info['sort_type'];
        }

        //获取分配产品渠道的ID
        if ($channel_group_id > 0) {
            $order_channel_id_and_nums = select_table_colom_muti(
                $db,
                'cz_channel_group_item',
                [
                    'channel_group_id' => intval($channel_group_id),
                ],
                [
                    ["CONCAT_WS('-',channel_id,submit_nums) as channel_id"]
                ]
            );
        } else {
            $order_channel_id_and_nums = select_table_colom_muti(
                $db,
                'cz_customer_product_channel',
                [
                    'customer_product_id' => $user_product['id'],
                ],
                [
                    ["CONCAT_WS('-',channel_id,submit_nums) as channel_id"]
                ]
            );
        }
    }
    $order_channel_ids = [];
    //次数map
    $order_channel_nums_map = [];
    foreach ($order_channel_id_and_nums as $v) {
        $tmp_arr = explode('-', $v);
        $id = $tmp_arr[0];
        $nums = $tmp_arr[1];
        $order_channel_nums_map[$id] = $nums;
        array_push($order_channel_ids, $id);
    }

    //按价格排序
    if ($channel_sort_type == 2) {
        $order_channel_ids = select_table_colom_muti(
            $db,
            'cz_channel_product',
            [
                'channel_id' =>  ['in', '(' . implode(",", $order_channel_ids) . ')'],
                'spec_id' => $spec_id
            ],
            [
                'channel_id'
            ],
            [
                ['channel_price', 'asc']
            ]
        );
        /*
        $order_channel_ids =  $db->db_getCol('SELECT channel_id FROM cz_channel_product WHERE channel_id IN (:channel_id) AND spec_id = :spec_id ORDER BY channel_price asc',[
            ':channel_id' => implode(",", $order_channel_ids),
            ':spec_id' => $spec_id
        ]);
        */

        $order_channel_id_and_nums_tmp = [];
        foreach ($order_channel_ids as $v) {
            array_push($order_channel_id_and_nums_tmp, "{$v}-{$order_channel_nums_map[$v]}");
        }
        $order_channel_id_and_nums = $order_channel_id_and_nums_tmp;
    }

    //获取id-次数
    return ['ids' => $order_channel_ids ?? [], 'id_num' => $order_channel_id_and_nums, 'is_loop' => $is_loop];
}

function check_hook($db, $order)
{
    $order_spec_id = $order['spec_id'];

    $order_province_id = $order['province_id'];
    $order_city_id = $order['city_id'];
    //0全国 1省份 2城市
    $hook_condit = -1;
    //user

    $has_city_hook = select_table_muti($db, 'cz_hook_spec', [
        'spec_id' => $order_spec_id,
        'city_id' => $order_city_id,
        'condit' => 2,
        'status' => 1
    ], [], [
        ['id', 'desc']
    ]);

    $hook_info = null;
    if ($has_city_hook) {
        $hook_info = $has_city_hook[0];
    } else {
        $has_province_hook = select_table_muti($db, 'cz_hook_spec', [
            'spec_id' => $order_spec_id,
            'province_id' => $order_province_id,
            'city_id' => 0,
            'condit' => 1,
            'status' => 1
        ], [], [
            ['id', 'desc']
        ]);
        if ($has_province_hook) {
            $hook_info = $has_province_hook[0];
        }
    }
    if (!$hook_info) {
        return [
            'hook' => 0,
            'act' => 0,
        ];
    }

    if ($hook_info['act'] == 3) {
        $channel_sort_type = $hook_info['sort_type'];

        $channel_product_id_and_nums = select_table_colom_muti(
            $db,
            'cz_hook_channel',
            [
                'hook_id' => $hook_info['id']
            ],
            [
                // ["CONCAT_WS('-',channel_product_id,submit_nums) as channel_product_id"]
                ["CONCAT_WS('-',channel_id,submit_nums) as channel_product_id"]
            ]
        );

        //  注意:这里查询返回的是channle_id,不是channel_product_id 2022 12/11修改
        $channel_product_ids = [];
        //次数map
        $channel_product_nums_map = [];
        foreach ($channel_product_id_and_nums as $v) {
            $tmp_arr = explode('-', $v);
            $channel_product_id = $tmp_arr[0];
            $nums = $tmp_arr[1];
            $channel_product_nums_map[$channel_product_id] = $nums;
            array_push($channel_product_ids, $channel_product_id);
        }

        //按价格排序
        if ($channel_sort_type == 2) {
            // $order_channel_ids =  $db->db_getCol('SELECT id FROM cz_channel_product WHERE id IN (:id) ORDER BY channel_price asc', [
            //     ':id' => implode(",", $channel_product_ids),
            // ]);
            $order_channel_ids =  $db->db_getCol('SELECT channel_id FROM cz_channel_product WHERE channel_id IN (:id) and product_id = :product_id and spec_id = :spec_id ORDER BY channel_price asc', [
                ':id' => implode(",", $channel_product_ids),
                ":product_id" => $order['product_id'],
                ":spec_id" => $order['spec_id']
            ]);
            $channel_product_id_and_nums_tmp = [];
            foreach ($order_channel_ids as $v) {
                array_push($channel_product_id_and_nums_tmp, "{$v}-{$channel_product_nums_map[$v]}");
            }
            $channel_product_id_and_nums = $channel_product_id_and_nums_tmp;
        }
    }

    return [
        'hook' => 1,
        'act' => $hook_info['act'] ?? 0,
        'id_num' => $channel_product_id_and_nums,
        'is_loop' => $hook_info['is_loop']
    ];
}

function insert_data_to_table($db, $table_name, $data)
{
    $sql = "insert into {$table_name} set ";
    foreach ($data as $key => $val) {
        $sql .= "{$key}='{$val}',";
    }
    $sql = substr($sql, 0, (strlen($sql) - 1));

    $lastInsertId = $db->db_query($sql, []);
    return $lastInsertId;
}
/**更新表数据*/
function update_table($db, $table_name, $data_params, $where_params)
{
    $sql = "UPDATE {$table_name} set ";
    foreach ($data_params as $k => $v) {
        if (is_array($v)) {
            $op = $v[0];
            $exp = $v[1];
            $sql .= "{$k} {$op} {$exp},";
        } else {
            $bind_key = ":DATA_{$k}";
            $sql .= "{$k} = {$bind_key},";
            $bind_params[$bind_key] = $v;
        }
    }
    $sql = substr($sql, 0, (strlen($sql) - 1));
    $sql .= " WHERE ";
    foreach ($where_params as $k => $v) {
        if (is_array($v)) {
            $op = $v[0];
            $exp = $v[1];
            $sql .= "{$k} {$op} {$exp} AND ";
        } else {
            $bind_key = ":WHERE_{$k}";
            $sql .= "{$k} = {$bind_key} AND ";
            $bind_params[$bind_key] = $v;
        }
    }
    if (empty($where_params)) {
        $sql = substr($sql, 0, (strlen($sql) - 7));
    } else {
        $sql = substr($sql, 0, (strlen($sql) - 4));
    }
    //    echo $sql.PHP_EOL;
    //    $file = "../api_resource/logs/".date("Ymd",time())."_sql.txt";
    //    file_put_contents($file,date("Y-m-d H:i:s")."  SQL: " . $sql . PHP_EOL,FILE_APPEND);
    $result = $db->db_query($sql, $bind_params);
    //    echo "影响行数：{$result}".PHP_EOL;
    return $result;
}
function get_select_table_sql($table_name, $where_params = [], $field_param = [], $sort_param = [])
{
    $field = '';
    if (!empty($field_param)) {
        foreach ($field_param as $v) {
            if (is_array($v)) {
                $op = $v[0];
                $field .= "{$op},";
            } else {
                $field .= "`{$v}`,";
            }
        }
        $field = substr($field, 0, (strlen($field) - 1));
    } else {
        $field = "*";
    }

    $order_by = "";
    if (!empty($sort_param)) {
        foreach ($sort_param as $v) {
            if (is_array($v)) {
                $sort_field = $v[0];
                $sort_type = $v[1] ?? 'ASC';
                $order_by .= "{$sort_field} {$sort_type},";
            } else {
                $order_by .= "$v,";
            }
        }
        $order_by = "ORDER BY " . substr($order_by, 0, (strlen($order_by) - 1));
    }


    $sql = "SELECT {$field} FROM `{$table_name}` ";
    if (!empty($where_params)) {
        $sql .= 'WHERE ';
        foreach ($where_params as $k => $v) {
            if (is_array($v)) {
                $op = $v[0];
                $exp = $v[1];
                $cond = $v[2] ?? 'AND';
                // "id = id+1 OR"
                $sql .= "{$k} {$op} {$exp} {$cond} ";
            } else {
                $bind_key = ":WHERE_{$k}";
                $sql .= "{$k} = {$bind_key} AND ";
                $bind_params[$bind_key] = $v;
            }
        }
        $sql = substr($sql, 0, (strlen($sql) - 4));
    }
    $sql .= " {$order_by}";

    $debug_sql = $sql;
    foreach ($bind_params as $k => $b) {
        $debug_sql = str_replace($k, $b, $debug_sql);
    }
    //    file_put_contents("../api_resource/logs/".date("Ymd",time())."_sql.txt",date("Y-m-d H:i:s")."  SQL: " . $debug_sql . PHP_EOL,FILE_APPEND);

    return ['sql' => $sql, 'bind_params' => $bind_params];
}
/**查询一条记录*/
function select_table_one($db, $table_name, $where_params = [], $field_param = [], $sort_param = [])
{

    $sql_info = get_select_table_sql($table_name, $where_params, $field_param, $sort_param);
    $sql = $sql_info['sql'];
    $bind_params = $sql_info['bind_params'];

    $sql .= " LIMIT 1";
    $result = $db->db_getRow($sql, $bind_params);
    return $result;
}
/**查询一条记录*/
function select_table_muti($db, $table_name, $where_params = [], $field_param = [], $sort_param = [], $limit = 0)
{

    $sql_info = get_select_table_sql($table_name, $where_params, $field_param, $sort_param);
    $sql = $sql_info['sql'];
    $bind_params = $sql_info['bind_params'];

    if ($limit > 0) {
        $sql .= " LIMIT {$limit}";
    }
    $result = $db->db_getAll($sql, $bind_params);
    return $result;
}
/**查询某一行的 一列值*/
function select_table_colom_one($db, $table_name, $where_params = [], $field_param = [], $sort_param = [])
{
    $sql_info = get_select_table_sql($table_name, $where_params, $field_param, $sort_param);
    $sql = $sql_info['sql'];
    $bind_params = $sql_info['bind_params'];

    $sql .= " LIMIT 1";
    $result = $db->db_getOne($sql, $bind_params);
    return $result;
}
/**查询一列值*/
function select_table_colom_muti($db, $table_name, $where_params = [], $field_param = [], $sort_param = [], $limit = 0)
{
    $sql_info = get_select_table_sql($table_name, $where_params, $field_param, $sort_param);
    $sql = $sql_info['sql'];
    $bind_params = $sql_info['bind_params'];

    if ($limit > 0) {
        $sql .= " LIMIT {$limit}";
    }
    $result = $db->db_getCol($sql, $bind_params);
    return $result;
}
function update_queue_order_status($db, $order_id, $queue_status)
{

    $sql = "update cz_order_queue set queue_status = :queue_status, updated_at = :updated_at WHERE order_id =:order_id";
    $result = $db->db_query($sql, [
        ':queue_status' => $queue_status,
        ':updated_at' => time(),
        ':order_id' => $order_id
    ]);
    return $result;
}
function update_cz_order_status($db, $order_id, $order_status, $msg)
{

    $sql = "update cz_order set order_status = :order_status, msg = :msg, updated_at = :updated_at WHERE id =:order_id";
    $result = $db->db_query($sql, [
        ':order_status' => $order_status,
        ':msg' => $msg,
        ':updated_at' => time(),
        ':order_id' => $order_id
    ]);
    return $result;
}
function sock_queue($order_id, $type, $params = [])
{
    global $config;
    $data = array_merge([
        'act' => $type,
        'order_id' => $order_id
    ], $params);
    sock_get($config['QUEUE_URL'], $data);
}
function order_fail($db, $msg, $order, $user, $product_info, $spec_info)
{
    global $config;
    //判断产品拦截失败
    if ($product_info['stop_fail'] == 1) {
        // 更改客户订单拦截
        update_cz_order_status($db, $order['id'], 6, substr("[拦截]" . $msg, 0, 100));
        return ['error' => 0, 'msg' => '操作成功'];
    } else {
        // 更改客户订单失败
        $is_update = update_cz_order_status($db, $order['id'], 4, $msg);
        if ($is_update) {
            $remark = "{$order['mobile']},充值[{$product_info['title']}{$spec_info['face_value']}]，退款{$order['price']}元";
            //退款
            $refund_res = order_refund($db, $order, $user, $remark);
            if ($order['callback_url']) {
                //回调队列
                $callback_queue_data = [
                    'order_id' => $order['id'],
                    'created_at' => time(),
                    'updated_at' => time(),
                ];
                $callback_queue_id = insert_data_to_table($db, 'cz_order_queue_callback', $callback_queue_data);
                //回调失败
                sock_queue($order['id'], 'callback_user_order');
                // 发送模版通知
                sock_get($config['ORDER_NORIFY_URL'], [
                    "order_id" => $order['id'],
                    "pwd" => "258963",
                    "type" => "fail"
                ]);
            }
            return ['error' => 0, 'msg' => '操作成功'];
        }
        //todo 回调客户
        $api_secret = $user['api_secret'];
        $callback_url = $order['callback_url'];
        if ($callback_url) {
            status_call_back($api_secret, $callback_url, [
                'order_sn' => $order['order_sn'],
                'user_order_sn' => $order['user_order_sn'],
                'order_status' => 4,
                'msg' => $msg
            ]);
        }
    }
    return ['error' => 1, 'msg' => '操作失败'];
}
function order_refund($db, $order, $user, $remark = '')
{
    global $config;
    sock_get($config['REFUND_URL'], [
        'order_id' => $order['id'],
        "pwd" => "774896",
        "order_remark" => $remark,
    ]);
    if ($order['plat_status'] == 0) {
        return ['error' => 1, 'msg' => '订单未扣款'];
    }
    if ($order['is_refund'] == 1) {
        return ['error' => 1, 'msg' => '订单已退过款'];
    }
    //检查是否有退款记录
    $refund_info = select_table_one($db, 'cz_order_refund_log', [
        'order_id' => $order['id']
    ]);
    if ($refund_info) {
        return ['error' => 1, 'msg' => '订单已退过款'];
    }

    if (!$remark) {
        $product_info = select_table_one($db, 'cz_product', [
            'id' => $order['product_id']
        ], ['id', 'title']);
        $spec_info = select_table_one($db, 'cz_spec', [
            'id' => $order['spec_id']
        ], ['id', 'face_value']);

        $remark = "{$order['mobile']},充值[{$product_info['title']}{$spec_info['face_value']}]，退款{$order['price']}元";
    }

    $user_balance_sql = "update sys_users set balance = balance + {$order['price']} where id = {$user['id']}";
    $is_refund_sql = "update cz_order set is_refund = 1, updated_at = :updated_at WHERE id =:order_id";

    //退款记录
    $balance_log_data = [
        'order_sn' => $order['order_sn'],
        'money' => $order['price'],
        'bf_balance' => $user['balance'],
        'af_balance' => $user['balance'] + $order['price'],
        'bank' => '',
        'type' => 4,
        'remark' => $remark,
        'user_id' => $user['id'],
        'created_at' => time(),
        'updated_at' => time(),
    ];

    $refund_log_data = [
        'order_id' => $order['id'],
        'created_at' => time(),
        'price' => $order['price'],
    ];
    try {
        $db->pdo->beginTransaction();

        $db->db_query($user_balance_sql);
        $db->db_query($is_refund_sql, [
            ':updated_at' => time(),
            ':order_id' => $order['id']
        ]);
        $balance_log_id = insert_data_to_table($db, 'balance_log', $balance_log_data);
        $refund_log_id = insert_data_to_table($db, 'cz_order_refund_log', $refund_log_data);

        $db->pdo->commit();
        return ['error' => 0, 'msg' => '订单已退款'];
    } catch (Exception $e) {
        $db->pdo->rollBack();
        $msg = $e->getMessage();
        file_put_contents("../api_resource/logs/" . date("Ymd") . "_queue_ll.log",  "[" . date("Y-m-d H:i:s") . "]" . "退款失败" . $msg . print_r($order, 1) . PHP_EOL, FILE_APPEND);
        return ['error' => 1, 'msg' => $msg];
    }
}

/*渠道回调成功*/
function channel_callback_success($db, $channel_order, $cz_order, $msg, $voucher = '')
{
    global $config;
    $msg = substr($msg, 0, 100);
    //更改渠道订单完成
    update_table($db, 'cz_channel_order', [
        'channel_order_status' => 3,
        'msg' => $msg,
        'updated_at' => time()
    ], [
        'id' => $channel_order['id']
    ]);

    //更改队列完成
    update_queue_order_status($db, $cz_order['id'], 3);

    // 更改客户订单完成
    // update_cz_order_status($db, $cz_order['id'], 3, $msg);
    $sql = "update cz_order set order_status = :order_status,voucher = :voucher, msg = :msg, updated_at = :updated_at WHERE id =:order_id";
    $result = $db->db_query($sql, [
        ':order_status' => 3,
        ':msg' => $msg,
        ':updated_at' => time(),
        ':order_id' => $cz_order['id'],
        ':voucher' => $voucher,
    ]);
    // return $result;

    sock_queue($cz_order['id'], 'callback_user_order');
    // 发送模版通知
    sock_get($config['ORDER_NORIFY_URL'], [
        "order_id" => $cz_order['id'],
        "pwd" => "258963",
        "type" => "success"
    ]);
    return true;
}
/*渠道回调失败*/
function channel_callback_fail($db, $channel_order, $cz_order, $msg)
{
    $msg = substr($msg, 0, 100);

    $order_sn =  $channel_order['order_sn'];
    //订单超时时间
    $cz_order_timeout = $cz_order['timeout'];
    $product_id = $cz_order['product_id'];
    $spec_id = $cz_order['spec_id'];

    $user = select_table_one($db, 'sys_users', [
        'id' => intval($cz_order['create_by'])
    ]);

    $product_info = select_table_one($db, 'cz_product', [
        'id' => $product_id
    ]);

    $spec_info = select_table_one($db, 'cz_spec', [
        'id' => $spec_id
    ]);

    //更改渠道订单失败
    update_table($db, 'cz_channel_order', [
        'channel_order_status' => 4,
        'msg' => $msg,
        'updated_at' => time()
    ], [
        'id' => $channel_order['id']
    ]);

    //订单超时(不分产品)
    $is_time_out = $cz_order_timeout > 0 && ($cz_order_timeout - time()) < 0;
    //超时或者终止订单
    if ($is_time_out || $cz_order['is_stop'] == 1) {
        //更改队列完成
        update_queue_order_status($db, $cz_order['id'], 3);
        //超时订单不进行拦截
        $product_info['stop_fail'] = 0;
        //订单失败
        order_fail($db, substr(($cz_order['is_stop'] ? "[终止]" : "[超时]") . $msg, 0, 100), $cz_order, $user, $product_info, $spec_info);


        return true;
    }

    //获取订单队列信息
    $order_queue = select_table_one($db, 'cz_order_queue', [
        'order_id' => $cz_order['id']
    ]);
    if (!$order_queue) {
        //        error('订单队列不存在');
        return true;
    }
    if ($order_queue['queue_status'] == 3) {
        //        error('订单已处理完成');
        return true;
    }
    //检查渠道订单是否有处理中的
    $channel_order = select_table_one($db, 'cz_channel_order', [
        'order_sn' => $order_sn,
        'channel_order_status' => ['IN', '(1,2)']
    ]);
    if ($channel_order) {
        //        error('有渠道订单正在处理');
        return true;
    }

    $channel_ids = explode(",", $order_queue['channel_queue']);

    $first_channel_id_info = array_shift($channel_ids);
    $channel_id_nums_arr = explode('-', $first_channel_id_info);
    $channel_id = $channel_id_nums_arr[0] ?? null;
    $channel_nums = $channel_id_nums_arr[1] ?? 0;

    //多渠道
    if ($channel_id) {
        // file_put_contents("../api_resource/logs/" . date("Ymd", time()) . "_sql.txt", date("Y-m-d H:i:s") . "  SQL: 有渠道 更改队列状态为待处理，循环订单channel_id 为false" . $channel_id  . PHP_EOL, FILE_APPEND);
        //有渠道 更改队列状态为待处理
        update_queue_order_status($db, $cz_order['id'], 1);
        //继续推送订单
        sock_queue($cz_order['id'], 'push_order');
    } else {
        //没有渠道 判断是否为无限循环
        //todo 以哪个循环判断为准 $order_queue['is_loop']
        if ($cz_order['is_loop'] == 0) {
            //不是循环订单 渠道跑完了
            //更改队列完成
            update_queue_order_status($db, $cz_order['id'], 3);
            //订单失败
            order_fail($db, $msg, $cz_order, $user, $product_info, $spec_info);

            return true;
        }
        // file_put_contents("../api_resource/logs/" . date("Ymd", time()) . "_sql.txt", date("Y-m-d H:i:s") . "  SQL: 循环订单channel_id 为false" . $channel_id  . PHP_EOL, FILE_APPEND);
        //循环订单
        // 单渠道回调失败又是无限重提
        update_queue_order_status($db, $cz_order['id'], 1);
        sock_queue($cz_order['id'], 'queue_order');
    }
    return true;
}

function status_call_back($api_secret, $url, $data)
{
    foreach ($data as $k => $v) {
        if (!$v) {
            unset($data[$k]);
        }
    }
    $api_key = get_api_secret($api_secret);
    $api_sign = api_sign($data, $api_key);
    $sign_str = api_sign_str($data, $api_key);
    $data['sign'] = $api_sign;

    $return_data = httpRequest(trim(html_entity_decode($url)), 'POST', $data);
    //记录回调
    $file = "../api_resource/logs/" . date("Ymd", time()) . "_usercallback.txt";
    //    $file = "./logs/".date("Ymd",time())."_callback.txt";

    $log['sign_str'] = $sign_str;
    $log['post_data'] = json_encode($data);
    $log['url'] = trim(html_entity_decode($url));
    $log['return_data'] = $return_data;
    $log['time'] = date('Y-m-d H:i:s', time());
    file_put_contents($file, print_r($log, 1), FILE_APPEND);
    return true;
}
function httpRequest($url, $method = 'GET', $postfields = null, $cookie = '', $refer = '', $headers = array(), $debug = false)
{
    //header("Content-type:text/html;charset=utf-8");
    $method = strtoupper($method);
    $ci = curl_init();
    /* Curl settings */
    curl_setopt($ci, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
    //        curl_setopt($ci, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:43.0) Gecko/20100101 Firefox/43.0");
    curl_setopt($ci, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.157 Safari/537.36");
    curl_setopt($ci, CURLOPT_CONNECTTIMEOUT, 60); /* 在发起连接前等待的时间，如果设置为0，则无限等待 */
    curl_setopt($ci, CURLOPT_TIMEOUT, 7); /* 设置cURL允许执行的最长秒数 */
    curl_setopt($ci, CURLOPT_RETURNTRANSFER, true);
    switch ($method) {
        case "POST":
            curl_setopt($ci, CURLOPT_POST, true);
            if (!empty($postfields)) {
                $tmpdatastr = is_array($postfields) ? http_build_query($postfields) : $postfields;
                curl_setopt($ci, CURLOPT_POSTFIELDS, $tmpdatastr);
            }
            break;
        default:
            curl_setopt($ci, CURLOPT_CUSTOMREQUEST, $method); /* //设置请求方式 */
            break;
    }
    $ssl = preg_match('/^https:\/\//i', $url) ? TRUE : FALSE;
    curl_setopt($ci, CURLOPT_URL, $url);
    if ($ssl) {
        curl_setopt($ci, CURLOPT_SSL_VERIFYPEER, FALSE); // https请求 不验证证书和hosts
        curl_setopt($ci, CURLOPT_SSL_VERIFYHOST, FALSE); // 不从证书中检查SSL加密算法是否存在
    }
    //curl_setopt($ci, CURLOPT_HEADER, true); /*启用时会将头文件的信息作为数据流输出*/
    curl_setopt($ci, CURLOPT_FOLLOWLOCATION, 1);
    curl_setopt($ci, CURLOPT_MAXREDIRS, 2);/*指定最多的HTTP重定向的数量，这个选项是和CURLOPT_FOLLOWLOCATION一起使用的*/
    curl_setopt($ci, CURLOPT_HTTPHEADER, $headers);
    curl_setopt($ci, CURLINFO_HEADER_OUT, true);
    curl_setopt($ci, CURLOPT_COOKIE, $cookie);/* * *COOKIE带过去** */
    //伪造来源referer
    //        curl_setopt ($ci,CURLOPT_REFERER,'http://sb777.cn:8080/tohersystem/rechargeOrder.do?action=distribution&isDistribution=true');
    curl_setopt($ci, CURLOPT_REFERER, $refer);

    $response = curl_exec($ci);
    $requestinfo = curl_getinfo($ci);
    $http_code = curl_getinfo($ci, CURLINFO_HTTP_CODE);
    if ($debug) {
        echo "=====post data======\r\n";
        var_dump($postfields);
        echo "=====info===== \r\n";
        print_r($requestinfo);
        echo "=====response=====\r\n";
        print_r($response);
    }
    curl_close($ci);
    return $response;
}
